#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
#include <cassert>
#include <vector>
#include <mutex>

using namespace std;

mutex mtx; // 全局互斥锁，保护输出

// 想传递的字段放到class 里面
class ThreadData
{
public:
    int number;
    pthread_t tid;
    char namebuffer[64];
};

class ThreadReturn
{
public:
    int exit_code;
    int exit_result;
};

// void* start_routine(void* args)
// {
//     // 一个线程如果出现了错误，会影响其它线程吗？(会的) 健壮性或者鲁棒性较差
//     //  为什么？ 进程信号，信号是整体发送给进程的。
//     string name = static_cast<const char*>(args); // 安全的进行强制类型转换
//     while(true)
//     {
//         cout<<"new thread create success, name : "<< name <<endl;
//         sleep(2);

//         // int* p =nullptr; 这是线程异常的时候代码
//         // *p = 0; // 访问空指针
//     }
// }

// 1.start_routine,现在被几个线程执行呢？ 10个， 这个函数现在是什么状态？可重入状态
// 2、该函数是可重入函数吗？ 是的
// 3、在函数内定义的变量，都叫做局部变量，具有临时性 --- 今天依旧适用 --
//  在多线程情况下，也没有问题 -- 其实每一个线程都有自己独立的栈结构！
void* start_routine(void* args)
{
    sleep(1);
    ThreadData *td = static_cast<ThreadData*> (args);
    int cnt = 10;
    while(cnt)
    {
        lock_guard<mutex> lock(mtx);
        // 看看会不会线程相互影响
        cout << "cnt: " << cnt << " &cnt: " << &cnt << endl; // bug
        cnt--;
        // cout<<"new thread create success, name : "<< td->namebuffer << " cnt: " << cnt-- <<endl;
       // sleep(1);
       // exit(0); // 能不能用来终止线程，不能。因为exit是终止进程的！任何一个执行流调用exit都会让整个进程退出
       // return nullptr; // 可以终止进程，但是一般不会写在中间，而是写在结束的位置
       // pthread_exit(nullptr); // 结束线程，一般写在结尾
    }

    //  线程如何终止的问题
    // delete td; //在外面申请和释放
    // pthread_exit(nullptr);

    // return nullptr; // 线程函数结束，return 的时候，线程就算终止了
    
   // return (void*)td->number; // warning, void *ret = (void*)td->number;

   // return (void*)111; // 让所有线程拿到同一个返回值
   // pthread_exit((void*)106); // 这样也能拿到同一个返回值

    // 既然假的地址，整数都能被外部拿到，那么如何返回的是，堆的地址空间呢？对象的地址呢？
    ThreadReturn *tr = new ThreadReturn();
    tr->exit_code = 1;
    tr->exit_result = 106;

    // ThreadReturn tr; // 不能这样写，因为这样是在栈上开辟的空间，这样会在结束的时候被销毁
    // tr.exit_code = 1;
    // tr.exit_result = 106;

    return (void*)tr; // 右值
}


int main()
{
    // 1.我们想创建一批线程
    // vector<pthread_t> tids;
    // #define NUM 10
    // for(size_t i = 0; i < NUM; i++)
    // {
    //     pthread_t tid;
    //     char namebuffer[64];
    //     snprintf(namebuffer,sizeof(namebuffer),"%s : %d","thread",i);
    //     // int n = pthread_create(&tid,nullptr,start_routine,(void*)"thread one");
    //     // int n = pthread_create(&tid,nullptr,start_routine,namebuffer); 
    //     sleep(1);
    // }

    vector<ThreadData*> threads;
    for(size_t i = 0; i < 10; i++)
    {
        ThreadData *td = new ThreadData();
        td->number = i + 1;
        snprintf(td->namebuffer,sizeof(td->namebuffer),"%s: %d", "thread", i + 1);
        int n = pthread_create(&td->tid,nullptr,start_routine,td);
        threads.push_back(td); // 把指针传里面
    }

    for(auto &iter:threads)
    {
        lock_guard<mutex> lock(mtx);
        cout << "create thread: " << iter->namebuffer << " : " << iter->tid << " success"<< endl;
        sleep(1);
    }
    sleep(5);

    // 线程是可以被cancel取消的！注意：线程要被取消，前提是这个线程已经跑起来了
    // 线程如果是被取消的，退出码:-1
    for(int i = 0; i < threads.size()/2; i++)
    {
        pthread_cancel(threads[i]->tid);
         cout << "pthread_cancel: "<< threads[i]->namebuffer << " success" << endl;
    }


    for(auto& iter : threads)
    {
        // 循环创建就循环等待
        ThreadReturn *ret = nullptr;
        // void *ret = nullptr;
        // int n = pthread_join(iter->tid,nullptr);
        // 想拿到pthread_join的第二个参数的返回值
        //int n = pthread_join(iter->tid,&ret); // void **retp; *retp = return (void*)td->nember;
        int n = pthread_join(iter->tid,(void**)&ret); // void **retp; *retp = return (void*)td->nember;
        assert(n == 0);
        // cout << "join: " << iter->namebuffer << " success, number"  << (long long)ret << endl; 
        // 必须是long long, Linux 下指针是8字节，否则转不过去
        
        // cout << "join: "<< iter->namebuffer << " success, exit_code: "  
        // << ret->exit_code << ", code_result: " << ret->exit_result << endl;

        cout << "join: " << iter->namebuffer << " success, exit_code"  << (long long)ret << endl; 

        delete iter; // 在外面释放
    } 

    cout << " main thread quit " << endl;

    // while(true)
    // {
    //     lock_guard<mutex> lock(mtx);
    //     cout<<"new thread create success, name :  main thread" <<endl;
    //     sleep(1);
    // }

    // 创建一个线程
    // pthread_t tid;
    // int n = pthread_create(&tid,nullptr,start_routine,(void*)"thread_one");

    // while(true)
    // {
    //     cout<<"new thread create success, name :  main thread" <<endl;
    //     sleep(1);
    // }
    return 0;
}